//! # 文件系统工具
//!
//! 提供文件和目录操作的工具函数

use crate::error::{CliError, CliResult};
use std::path::Path;
use tokio::fs;

/// 创建目录（递归）
pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> CliResult<()> {
    fs::create_dir_all(path).await.map_err(CliError::from)
}

/// 复制文件
pub async fn copy_file<P: AsRef<Path>>(from: P, to: P) -> CliResult<()> {
    if let Some(parent) = to.as_ref().parent() {
        create_dir_all(parent).await?;
    }
    fs::copy(from, to).await.map_err(CliError::from)?;
    Ok(())
}

/// 复制目录（递归）
pub async fn copy_dir<P: AsRef<Path>>(from: P, to: P) -> CliResult<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    create_dir_all(to).await?;

    let mut entries = fs::read_dir(from).await?;
    while let Some(entry) = entries.next_entry().await? {
        let entry_path = entry.path();
        let file_name = entry.file_name();
        let dest_path = to.join(&file_name);

        if entry_path.is_dir() {
            copy_dir(&entry_path, &dest_path).await?;
        } else {
            copy_file(&entry_path, &dest_path).await?;
        }
    }

    Ok(())
}

/// 检查文件是否存在
pub async fn file_exists<P: AsRef<Path>>(path: P) -> bool {
    fs::metadata(path).await.is_ok()
}

/// 检查目录是否为空
pub async fn is_dir_empty<P: AsRef<Path>>(path: P) -> CliResult<bool> {
    let mut entries = fs::read_dir(path).await?;
    Ok(entries.next_entry().await?.is_none())
}

/// 获取文件大小
pub async fn file_size<P: AsRef<Path>>(path: P) -> CliResult<u64> {
    let metadata = fs::metadata(path).await?;
    Ok(metadata.len())
}

/// 删除文件或目录
pub async fn remove_all<P: AsRef<Path>>(path: P) -> CliResult<()> {
    let path = path.as_ref();
    if path.is_file() {
        fs::remove_file(path).await?;
    } else if path.is_dir() {
        fs::remove_dir_all(path).await?;
    }
    Ok(())
}